// =====================================================================================
// 
//       Filename:  protocol.c
// 
//    Description:  Implementation of functions used to communicate with the remote
//    				web service
// 
//        Version:  1.0
//        Created:  22/09/2010 23:25:11
//       Revision:  none
//       Compiler:  gcc
// 
//         Author:  François Hissel (fh), francois.hissel@m4x.org
//        Company:  
// 
// =====================================================================================

#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<time.h>
#include	<sys/mman.h>
#include	<pthread.h>
#include	"pathutils.h"
#include	"protocol.h"

void init_resources() {
	persistent.cookies=0;
	persistent.host=0;
	persistent.tree=0;
	persistent.hostinfo=0;
	persistent.username=0;
	persistent.password=0;
	pthread_mutex_init(&persistent.lock,0);
}

void free_resources() {
	free_cookies(persistent.cookies);
	free(persistent.host);
	free_folder(persistent.tree);
	freeaddrinfo(persistent.hostinfo);
	free(persistent.username);
	free(persistent.password);
}

/**
 * \brief Get page from remote server
 *
 * This function gets a page from the remote server, from the chosen path, and saves it in a newly created temporary file, which pointer is returned. It adds automatically a NULL character at the end of the file, so that it can be mapped to a null-terminated string on which standard string functions may be called. At the end of the function, the temporary file is still open with the file position indicator at the beginning of it.
 * \param path Path name on the remote server
 * \param body Body of the request, for a POST request. For a GET request, this variable should be 0
 * \param size Size of the downloaded file
 * \return a descriptor on the temporary file with the contents of the website if everything went fine, a NULL pointer otherwise
 */
FILE* get_page(const char *path,const char *body,unsigned long *size) {
	FILE *fd=tmpfile();	
	if (fd==0) return 0;
	*size=request_addr(fd,persistent.hostinfo,persistent.host,path,body,&(persistent.cookies));
	fprintf(fd,"%c",'\000');
	if (*size<0) return 0;
	++(*size);
	rewind(fd);
	return fd;
}

int connect_service(char *host,char *port,char *user,char *password) {
	// Store username and password in case it is needed to reconnect
	pthread_mutex_lock(&persistent.lock);
	persistent.username=malloc(strlen(user)+1);
	persistent.password=malloc(strlen(password)+1);
	strcpy(persistent.username,user);
	strcpy(persistent.password,password);
	// Resolve host name
	char *phost;
	char *pport;
	if (proxy[0]==0) {	// If a proxy is selected, use it in the request, else connect directly to the website
		phost=host;
		pport=port;
	} else {
		phost=proxy;
		pport=proxy_port;
	}
	persistent.host=(char*)malloc(strlen(host)+1);
	strcpy(persistent.host,host);
	if (resolve(phost,pport,&(persistent.hostinfo))!=0) {
		fprintf(stderr,"Can't resolve address : %s\n",phost);
		pthread_mutex_unlock(&persistent.lock);
		return -1;
	}
	// Start of procedure
	char path[PATH_SIZE];	// Path of the web page on the remote server
	FILE *fd;	// Temporary file to save the contents of the web pages
	if (persistent.cookies!=0) free_cookies(persistent.cookies);
	persistent.cookies=0;	// List of cookies
	// First request, main page
	strcpy(path,"/n/1-3/");
	size_t size=31+strlen(user)+strlen(password);	// Length of the request body
	unsigned long psize;	// Size of the body of the response
	char *body;	// Request body
	body=(char*)malloc(size);
	sprintf(body,"user=%s&pass=%s&submittheform=Save",user,password);
	fd=get_page(path,body,&psize);
	free(body);
	if (fd==0) {
		pthread_mutex_unlock(&persistent.lock);
		return -1;
	}
	// Find address of main page and get the ID cookie
	char *page=mmap(0,psize,PROT_READ,MAP_SHARED,fileno(fd),0);	// Pointer to the response
	fclose(fd);
	if (page==MAP_FAILED) {
		pthread_mutex_unlock(&persistent.lock);
		return -1;
	}
	char *p=strstr(page,"form name=\"main\" id=\"main\"");
	if (p==0) {
		munmap((void*)page,psize);
		pthread_mutex_unlock(&persistent.lock);
		return -1;
	}
	p+=35;
	char *q=strstr(p,host);
	if (q!=0) p=q+strlen(host);
	q=strchr(p,'\"');
	if (q==0) {
		munmap((void*)page,psize);
		pthread_mutex_unlock(&persistent.lock);
		return -1;
	}
	char mainpath[PATH_SIZE];
	strncpy(mainpath,p,q-p);
	mainpath[q-p]=0;
	munmap((void*)page,psize);
	// Second page: connection established, get a fixed path for the root folder
	Cookies *id=get_cookie(persistent.cookies,"PHPSESSID");
	if (id==0) return -1;
	size=256+strlen(id->cookie.value);
	body=(char*)malloc(size);
	sprintf(body,"JavaVendor=Unknown&JavaVersion=Unknown&appCodeName=Mozilla&appName=Netscape&appVersion=5.0&cookieEnabled=true&language=fr&availHeight=1176&availWidth=1280&colorDepth=24&height=1024&width=1280&innerWidth=1280&innerHeight=769&PHPSESSID=%s&flashVersion=Unknown",id->cookie.value);
	fd=get_page(mainpath,body,&psize);
	free(body);
	if (fd==0) {
		pthread_mutex_unlock(&persistent.lock);
		return -1;
	}
	page=mmap(0,psize,PROT_READ,MAP_SHARED,fileno(fd),0);	// Pointer to the response
	fclose(fd);
	if (page==MAP_FAILED) {
		pthread_mutex_unlock(&persistent.lock);
		return -1;
	}
	p=strstr(page,"Disque virtuel");
	if (p==0) {
		munmap((void*)page,psize);
		pthread_mutex_unlock(&persistent.lock);
		return -1;
	}
	int i=0;
	while (p>page && i<2) {
		if (*p=='<') ++i;
		--p;
	}
	if (p<=page) {
		munmap((void*)page,psize);
		pthread_mutex_unlock(&persistent.lock);
		return -1;
	}
	p=strchr(p,'"')+1;
	q=strchr(p,'"');
	if (q==0) {
		munmap((void*)page,psize);
		pthread_mutex_unlock(&persistent.lock);
		return -1;
	}
	if (persistent.tree!=0) free_folder(persistent.tree);
	persistent.tree=create_folder(0);
	persistent.tree->file->path=malloc(q-p+1);
	strncpy(persistent.tree->file->path,p,q-p);
	persistent.tree->file->path[q-p]=0;
	persistent.tree->file->name=malloc(sizeof(2));
	strcpy(persistent.tree->file->name,"/");
	persistent.tree->file->type=T_FOLDER;
	munmap((void*)page,psize);
	// Add a useful cookie: by faking the website to think that our screen is high, we get it to send more data on each page, therefore it speeds up the accesses to a file or the listings of a directory
	Cookies *cook=(Cookies*)malloc(sizeof(Cookies));
	cook->cookie.name=(char*)malloc(11);strcpy(cook->cookie.name,"pagination");
	cook->cookie.value=(char*)malloc(11);strcpy(cook->cookie.value,"1280%7C969");
	cook->next=persistent.cookies;
	persistent.cookies=cook;
	pthread_mutex_unlock(&persistent.lock);
	return 0;
}

/**
 * \brief Read the contents of a folder from the remote web site
 *
 * This functions reads the contents of the folder which can be accessed through the path remotepath on the distant web server. It can optionnally store the contents of the folder in the content variable.
 * \param folder  Pointer to a Folder variable in which the content of the remote folder will be stored. The actual files will be stored in the elements field. The Folder structure should already contain the path of the folder on the server (in the file field)
 * \param refresh If refresh=1, force a reload of the folder from the remote server
 * \return 0 if everything went fine, another value otherwise
 */
int get_folder(Folder *folder,int refresh) {
	if (refresh!=1 && folder->file->updated==1) return 0;
	// Get first page
	unsigned long psize;
	FILE *fd=get_page(folder->file->path,0,&psize);
	if (fd==0) return -1;
	char *page=mmap(0,psize,PROT_READ,MAP_SHARED,fileno(fd),0);	// Pointer to the response
	fclose(fd);
	if (page==MAP_FAILED) {return -1;}
	// Clean the folder structure
	pthread_mutex_lock(&persistent.lock);
	if (folder->elements!=0) {
		free_folder(folder->elements);
		folder->elements=0;
	}
	if (folder->file->requesturi!=0) free(folder->file->requesturi);
	pthread_mutex_unlock(&persistent.lock);
	// Get the request URi
	char *pos=strstr(page,"xajaxRequestUri");
	if (pos==0) return -1;
	pos+=17;
	char *q=strchr(pos,'"');
	if (q==0) return -1;
	pthread_mutex_lock(&persistent.lock);
	folder->file->requesturi=malloc(q-pos+1);
	strncpy(folder->file->requesturi,pos,q-pos);
	folder->file->requesturi[q-pos]=0;
	pthread_mutex_unlock(&persistent.lock);
	// Get number of pages
	int number_page;	// Number of pages
	pos=strstr(page,"div class=\"navig\"");
	if (pos==0 || strncmp(pos+19,"</div>",6)==0) number_page=1; else {
		char *q,*r;
		q=pos;r=q;
		while (q!=0) {
			q=strstr(q+1,"/list/page/");
			if (q!=0) r=q;
		}
		number_page=atoi(r+11);
		if (number_page<=0) {munmap((void*)page,psize);return -1;}
	}
	// Get generic address of pages
	char *r;
	char generic[PATH_SIZE];
	if (number_page>1) {
		pos=strstr(pos,"<a href=")+9;
		if (pos==0) {munmap((void*)page,psize);return -1;}
		q=strchr(pos,'"');
		if (q==0) {munmap((void*)page,psize);return -1;}
		--q;
		while (*q=='/') --q;
		while (*q>='0' && *q<='9') --q;
		strncpy(generic,pos,q-pos+1);
		r=generic+(q-pos)+1;
	}
	// Get contents of folder
	int i;
	Folder *current=folder->elements;	// End of the list of items in the folder
	for (i=1;i<=number_page;++i) {
		if (i>1) {
			munmap((void*)page,psize);
			sprintf(r,"%i/",i);
			fd=get_page(generic,0,&psize);
			if (fd==0) return -1;
			page=mmap(0,psize+1,PROT_READ,MAP_SHARED,fileno(fd),0);	// Pointer to the response
			fclose(fd);
			if (page==MAP_FAILED) return -1;
		}
		pos=page;
		while (pos!=0) {
			char path[PATH_SIZE];
			pos=strstr(pos,"class=\"AGTrgTooltip\" title=");
			if (pos==0) continue;
			pos=strstr(pos,"<a href=");
			if (pos==0) continue;
			pos+=9;
			q=strchr(pos,'"');
			strncpy(path,pos,q-pos);
			path[q-pos]=0;
			pos=strstr(pos,"alt=");
			if (pos==0) continue;
			pos+=5;
			q=strchr(pos,'"');
			if (q==0) continue;
			char file[PATH_SIZE];
			char file2[PATH_SIZE];
			strncpy(file,pos,q-pos);
			file[q-pos]=0;
			html_to_text(file,file2);
			//printf("%s\n",file2);
			// Create new structure and add it in the list of elements of the current folder
			pthread_mutex_lock(&persistent.lock);
			Folder *newfolder=create_folder(folder);
			if (current==0) {
				current=newfolder;
				folder->elements=current;
			} else {
				current->next=newfolder;
				current=newfolder;
			}
			// Get path and name of the file
			newfolder->file->name=malloc(strlen(file2)+1);
			newfolder->file->path=malloc(strlen(path)+1);
			strcpy(newfolder->file->name,file2);
			strcpy(newfolder->file->path,path);
			// Get type of the file
			if (strstr(path,"folder")==0) newfolder->file->type=T_FILE; else newfolder->file->type=T_FOLDER;
			// Find date of last modification
			pos=strstr(pos,"<span style=\"");
			if (pos==0) {pthread_mutex_unlock(&persistent.lock);continue;}
			pos=strchr(pos,'>');
			if (pos==0) {pthread_mutex_unlock(&persistent.lock);continue;}
			pos++;
			struct tm modif;
			modif.tm_mday=atoi(pos);
			modif.tm_mon=atoi(pos+3)-1;
			modif.tm_year=atoi(pos+6)-1900;
			modif.tm_hour=atoi(pos+13);
			modif.tm_min=atoi(pos+16);
			modif.tm_sec=0;modif.tm_isdst=0;modif.tm_wday=0;modif.tm_yday=0;
			newfolder->file->date=mktime(&modif);
			// Find size of file
			pos=strstr(pos,"<span style=\"");
			if (pos==0) {pthread_mutex_unlock(&persistent.lock);continue;}
			pos=strchr(pos,'>');
			if (pos==0) {pthread_mutex_unlock(&persistent.lock);continue;}
			pos++;
			double value=atof(pos);
			while (*pos!=0 && *pos!=';') ++pos;
			if (*pos==0) {pthread_mutex_unlock(&persistent.lock);continue;}
			++pos;
			if (strncmp(pos,"Go",2)==0) newfolder->file->size=(ssize_t)(value*(1 << 30));
			else if (strncmp(pos,"Mo",2)==0) newfolder->file->size=(ssize_t)(value*(1 << 20));
			else if (strncmp(pos,"Ko",2)==0) newfolder->file->size=(ssize_t)(value*(1 << 10));
			else if (strncmp(pos,"octet",5)==0) newfolder->file->size=(ssize_t)(value);
			pthread_mutex_unlock(&persistent.lock);
		}
	}
	munmap((void*)page,psize+1);
	folder->file->updated=1;
	return 0;
}

/**
 * \brief Find the remote path corresponding to a path name or a file name
 *
 * This function looks for the path where a folder can be accessed on the web server. It first goes through an intenal data structure, tree. If the folder is not found in tree, the function then goes through the whole tree on the remoter server to find the remote path name associated with the chosen folder or file. A pointer to the folder structure in memory is returned in the item variable. The remote path can be accessed through *item->file->path. The function returns 0 if everything went fine and another value otherwise.
 * \param path Name of the local path
 * \param tree Internal representation of the distant file tree, as stored in memory
 * \param item At the end of the function, this variable will point to the folder representation in memory 
 * \return 0 if everything went fine, -1 if an error occurred, and 1 if the folder or file could not be found
 */
int find_folder(const char *path,Folder *tree,Folder **item) {
	if (*path==0 || (*path=='/' && path[1]==0)) {
		*item=persistent.tree;
		return 0;
	}
	char localpath[PATH_SIZE];	// Simplified local path name
	char name[PATH_SIZE];	// Name of the current path
	path_simplify(path,localpath);
	const char *pos=localpath;	// Position of the path which is being dealt with
	//char tmp[PATH_SIZE];
	Folder *cur=tree;	// cur is the current leaf in the tree
	Folder *children;	// Elements of the current folder cur
	while (*pos!=0) {
		get_dir(&pos,name);
		//text_to_html(name,tmp);
		if (get_folder(cur,0)!=0) {
			return -1;	// If the folder has not been loaded or the item is not found, reload the folder from the web server
		}
		pthread_mutex_lock(&persistent.lock);
		children=find_item(cur->elements,name);
		pthread_mutex_unlock(&persistent.lock);
		if (children!=0) {	// Try to find the address in memory
			cur=children;
		} else {
			return 1;	// The file could not be found
		}
	}
	*item=cur;
	return 0;
}

int get_node(const char *path,Folder **folder) {
	if (find_folder(path,persistent.tree,folder)!=0) return -1;
	if ((*folder)->file->type==T_FOLDER) {	// Folder not yet loaded
		if (get_folder(*folder,0)!=0) return -1;
	}
	return 0;
}

int list_folder(const char *folder) {
	Folder *item;
	int code=find_folder(folder,persistent.tree,&item);
	if (code!=0) return code;
	code=get_folder(item,0);
	if (code!=0) return code;
	item=item->elements;
	//char name[PATH_SIZE];
	while (item!=0) {
		//html_to_text(item->file->name,name);
		printf("%s\n",item->file->name);
		item=item->next;
	}
	return 0;
}

int download_file(const char *path,const char *localpath) {
	Folder *fold;
	int code=find_folder(path,persistent.tree,&fold);
	if (code!=0) return code;
	FILE *file=fopen(localpath,"w");
	if (file==0) return -1;
	if (fold->file->path==0) {	// If the file does not have a path (may occur for a newly created one)
		if (get_folder(fold->parent,1)!=0) return -1;
	}
	request_addr(file,persistent.hostinfo,persistent.host,fold->file->path,0,&(persistent.cookies));
	fclose(file);
	return 0;
}

int upload_file(const char *pathname,const char* filename,const char *file) {
	// Go to the remote folder
	Folder *fold;
	int code=find_folder(pathname,persistent.tree,&fold);
	if (code!=0) return code;
	// Get the number of the folder
	char id[20];
	get_id(fold,id);
	// Get the time (this number is sent with the parameters of the request, so I keep it this way). The time is expressed in number of milliseconds since January 1st, 1970, in the Unix fashion
	time_t tt=time(0);
	char stime[20];
	sprintf(stime,"%li000",(unsigned long)tt);
	// Load the folder and find the address of the upload request. 
	if (get_folder(fold,1)!=0) return -1;
	//if (send_custom(0,persistent.hostinfo,persistent.host,fold->file->path,"",0,persistent.cookies)!=0) return -1;	// Send a request to reload the directory of upload since it appears to be needed by the remote webserver (the xajaxargs param later is not enough to select the upload destination)
	// Now post a request to run the AJAX application used to upload new files, and get the address of the page on which the file has to be uploaded
	char uploaduri[PATH_SIZE];
	size_t bsize=60+strlen(stime)+strlen(id);
	char *body=(char*)malloc(bsize);
	sprintf(body,"xajax=newajax_ajaxupload_depot_fichier&xajaxr=%s&xajaxargs[]=%s",stime,id);
	unsigned long psize;
	FILE *fd=get_page(fold->file->requesturi,body,&psize);
	free(body);
	if (fd==0) return -1;
	char *page=mmap(0,psize+1,PROT_READ,MAP_SHARED,fileno(fd),0);	// Pointer to the response
	fclose(fd);
	if (page==MAP_FAILED) return -1;
	char *p=strstr(page,"class=\"form\" action=");
	if (p==0) {munmap((void*)page,psize);return -1;}
	p+=21;
	char *q=strchr(p,'"');
	if (q==0) {munmap((void*)page,psize);return -1;}
	strncpy(uploaduri,p,q-p);
	uploaduri[q-p]=0;
	munmap((void*)page,psize);
	// Now upload the actual file through a POST request
	FILE *f=fopen(file,"r");
	if (f==0) {
		fprintf(stderr,"Could not find file %s\n",file);
		return -1;
	}
	fseek(f,0,SEEK_END);
	ssize_t filesize=ftell(f);
	rewind(f);
	code=upload_request(persistent.hostinfo,persistent.host,uploaduri,filename,f,filesize,persistent.cookies);
	fclose(f);
	if (code!=0) {
		fprintf(stderr,"Could not write file\n");
		return -1;
	}
	// Add the file to the directory structure in memory
	pthread_mutex_lock(&persistent.lock);
	Folder *newfolder=create_folder(fold);
	newfolder->file->name=malloc(strlen(filename)+1);
	strcpy(newfolder->file->name,filename);
	newfolder->file->type=T_FILE;
	newfolder->file->size=filesize;
	time(&(newfolder->file->date));
	newfolder->next=fold->elements;
	fold->elements=newfolder;
	pthread_mutex_unlock(&persistent.lock);
	// Release resources and exit
	return 0;
}

int move_file(const char *source,const char *dest) {
	// Get the time (this number is sent with the parameters of the request, so I keep it this way). The time is expressed in number of milliseconds since January 1st, 1970, in the Unix fashion
	time_t tt=time(0);
	char stime[20];
	sprintf(stime,"%li000",(unsigned long)tt);
	// Get the source and destination paths
	char tmp[PATH_SIZE],tmp2[PATH_SIZE];
	char sourcename[PATH_SIZE];
	char sourceid[PATH_SIZE];
	char destpath[PATH_SIZE];
	char destname[PATH_SIZE];
	char destid[PATH_SIZE];
	char actionuri[PATH_SIZE];
	Folder *sourcefold,*sourcefile,*destfold;
	unsigned long psize,bsize;
	char *sep="----------------------1345564553545";
	size_t lsep=strlen(sep);;
	char *head,*body,*p,*q,*page;
	FILE *fd;
	get_path_and_name(source,tmp,sourcename);
	int code=find_folder(tmp,persistent.tree,&sourcefold);
	if (code!=0) return code;
	get_path_and_name(dest,tmp2,destname);
	if (strcmp(tmp,tmp2)!=0) {
		code=find_folder(tmp2,persistent.tree,&destfold);
		if (code==-1) return -1; else if (code==1) return 2;
		get_id(destfold,destid);	// Get the number of the destination folder
		strcpy(destpath,destfold->file->path);
		// Load the source folder and select the source file
		if (get_folder(sourcefold,1)!=0) return -1;
		sourcefile=find_item(sourcefold->elements,sourcename);
		if (sourcefile==0) return -1;
		get_id(sourcefile,sourceid);
		// Select the file
		if (sourcefile->file->type==T_FILE) {
			bsize=85+strlen(stime)+strlen(sourceid);
			body=(char*)malloc(bsize);
			sprintf(body,"xajax=newajax_fichiers_switch_basket_element&xajaxr=%s&xajaxargs[]=file&xajaxargs[]=%s",stime,sourceid);
		} else {
			bsize=87+strlen(stime)+strlen(sourceid);
			body=(char*)malloc(bsize);
			sprintf(body,"xajax=newajax_fichiers_switch_basket_element&xajaxr=%s&xajaxargs[]=folder&xajaxargs[]=%s",stime,sourceid);
		}
		send_custom(0,persistent.hostinfo,persistent.host,sourcefold->file->requesturi,http_post_form,body,persistent.cookies);
		free(body);
		// Send a request for the move form and retrieve the action URi
		bsize=41+strlen(stime);
		body=(char*)malloc(bsize);
		sprintf(body,"xajax=newajax_ajaxfichiers_move&xajaxr=%s",stime);
		fd=get_page(sourcefold->file->requesturi,body,&psize);
		free(body);
		if (fd==0) return -1;
		page=mmap(0,psize+1,PROT_READ,MAP_SHARED,fileno(fd),0);	// Pointer to the response
		fclose(fd);
		if (page==MAP_FAILED) return -1;
		p=strstr(page,"id=\"AgTgtMoveForm\" action=\"");
		if (p==0) {munmap((void*)page,psize);return -1;}
		p+=27;
		q=strchr(p,'"');
		strncpy(actionuri,p,q-p);
		actionuri[q-p]=0;
		munmap((void*)page,psize);
		// Finally, send the move command to the destination folder
		head=malloc(47+lsep);
		sprintf(head,"Content-Type: multipart/form-data; boundary=%s\r\n",sep);
		bsize=73+2*strlen(sep)+strlen(destid);
		body=(char*)malloc(bsize);
		sprintf(body,"--%s\r\nContent-Disposition: form-data; name=\"folders\"\r\n\r\n%s\r\n--%s--\r\n",sep,destid,sep);
		code=send_custom(0,persistent.hostinfo,persistent.host,actionuri,head,body,persistent.cookies);
		free(head);
		free(body);
		if (code!=0) return code;
	} else {
		destfold=sourcefold;
		get_id(destfold,destid);
	}
	// Now, do we have to rename the file ?
	if (strcmp(sourcename,destname)==0) return 0;
	// Load the source folder and select the source file
	if (get_folder(destfold,1)!=0) return -1;
	sourcefile=find_item(destfold->elements,sourcename);
	if (sourcefile==0) return -1;
	get_id(sourcefile,sourceid);
	// Select the file
	if (sourcefile->file->type==T_FILE) {
		bsize=85+strlen(stime)+strlen(sourceid);
		body=(char*)malloc(bsize);
		sprintf(body,"xajax=newajax_fichiers_switch_basket_element&xajaxr=%s&xajaxargs[]=file&xajaxargs[]=%s",stime,sourceid);
	} else {
		bsize=87+strlen(stime)+strlen(sourceid);
		body=(char*)malloc(bsize);
		sprintf(body,"xajax=newajax_fichiers_switch_basket_element&xajaxr=%s&xajaxargs[]=folder&xajaxargs[]=%s",stime,sourceid);
	}
	send_custom(0,persistent.hostinfo,persistent.host,destfold->file->requesturi,http_post_form,body,persistent.cookies);
	free(body);
	// Send a request for the rename form and retrieve the action URi
	bsize=44+strlen(stime);
	body=(char*)malloc(bsize);
	sprintf(body,"xajax=newajax_ajaxfichiers_renommer&xajaxr=%s",stime);
	fd=get_page(destfold->file->requesturi,body,&psize);
	free(body);
	if (fd==0) return -1;
	page=mmap(0,psize+1,PROT_READ,MAP_SHARED,fileno(fd),0);	// Pointer to the response
	fclose(fd);
	if (page==MAP_FAILED) return -1;
	p=strstr(page,"id=\"AgTgtRenameForm\" class=\"form\" action=\"");
	if (p==0) {munmap((void*)page,psize);return -1;}
	p+=42;
	q=strchr(p,'"');
	strncpy(actionuri,p,q-p);
	actionuri[q-p]=0;
	munmap((void*)page,psize);
	// Finally, send the move command to the destination folder
	head=malloc(47+lsep);
	sprintf(head,"Content-Type: multipart/form-data; boundary=%s\r\n",sep);
	bsize=310+6*lsep+strlen(sourceid)+strlen(destname);
	body=(char*)malloc(bsize);
	sprintf(body,"--%s\r\nContent-Disposition: form-data; name=\"id_file\"\r\n\r\n%s\r\n--%s\r\nContent-Disposition: form-data; name=\"rename_files_ok_x\"\r\n\r\nok\r\n--%s\r\nContent-Disposition: form-data; name=\"filename\"\r\n\r\n%s\r\n--%s\r\nContent-Disposition: form-data; name=\"id_parent\"\r\n\r\n\r\n--%s\r\nContent-Disposition: form-data; name=\"submitButton\"\r\n\r\nAdd\r\n--%s--\r\n",sep,sourceid,sep,sep,destname,sep,sep,sep);
	code=send_custom(0,persistent.hostinfo,persistent.host,actionuri,head,body,persistent.cookies);
	free(body);
	free(head);
	// Make the tree structure in memory out of date
	pthread_mutex_lock(&persistent.lock);
	free_folder(destfold->elements);
	destfold->elements=0;
	destfold->file->updated=0;
	remove_element(sourcefold,sourcename);
	pthread_mutex_unlock(&persistent.lock);
	// Exit
	return code;
}

int delete_file(const char *path) {
	// Get the time (this number is sent with the parameters of the request, so I keep it this way). The time is expressed in number of milliseconds since January 1st, 1970, in the Unix fashion
	time_t tt=time(0);
	char stime[20];
	sprintf(stime,"%li000",(unsigned long)tt);
	// Get the source and destination paths
	char tmp[PATH_SIZE];
	char sourcename[PATH_SIZE];
	char sourceid[PATH_SIZE];
	char actionuri[PATH_SIZE];
	unsigned long psize,bsize;
	char *sep="----------------------1345564553545";
	size_t lsep=strlen(sep);;
	char *head,*body,*p,*q,*page;
	FILE *fd;
	get_path_and_name(path,tmp,sourcename);
	Folder *fold,*sourcefile;
	int code=find_folder(tmp,persistent.tree,&fold);
	if (code!=0) return code;
	// Load the source folder
	if (get_folder(fold,1)!=0) return -1;
	sourcefile=find_item(fold->elements,sourcename);
	if (sourcefile==0) return 1;
	get_id(sourcefile,sourceid);
	// Select the file
	if (sourcefile->file->type==T_FILE) {
		bsize=85+strlen(stime)+strlen(sourceid);
		body=(char*)malloc(bsize);
		sprintf(body,"xajax=newajax_fichiers_switch_basket_element&xajaxr=%s&xajaxargs[]=file&xajaxargs[]=%s",stime,sourceid);
	} else {
		bsize=87+strlen(stime)+strlen(sourceid);
		body=(char*)malloc(bsize);
		sprintf(body,"xajax=newajax_fichiers_switch_basket_element&xajaxr=%s&xajaxargs[]=folder&xajaxargs[]=%s",stime,sourceid);
	}
	send_custom(0,persistent.hostinfo,persistent.host,fold->file->requesturi,http_post_form,body,persistent.cookies);
	free(body);
	// Send a request for the delete form and retrieve the action URi
	bsize=43+strlen(stime);
	body=(char*)malloc(bsize);
	sprintf(body,"xajax=newajax_ajaxfichiers_delete&xajaxr=%s",stime);
	fd=get_page(fold->file->requesturi,body,&psize);
	free(body);
	if (fd==0) return -1;
	page=mmap(0,psize+1,PROT_READ,MAP_SHARED,fileno(fd),0);	// Pointer to the response
	fclose(fd);
	if (page==MAP_FAILED) return -1;
	p=strstr(page,"id=\"AgTgtdeleteForm\" action=\"");
	if (p==0) {munmap((void*)page,psize);return -1;}
	p+=29;
	q=strchr(p,'"');
	strncpy(actionuri,p,q-p);
	actionuri[q-p]=0;
	munmap((void*)page,psize);
	// Finally, send the delete command
	head=malloc(47+lsep);
	sprintf(head,"Content-Type: multipart/form-data; boundary=%s\r\n",sep);
	bsize=71+2*strlen(sep);
	body=(char*)malloc(bsize);
	sprintf(body,"--%s\r\nContent-Disposition: form-data; name=\"dothesubmit\"\r\n\r\nSave\r\n--%s--\r\n",sep,sep);
	code=send_custom(0,persistent.hostinfo,persistent.host,actionuri,head,body,persistent.cookies);
	free(head);
	free(body);
	if (code!=0) return code;
	// Update the tree structure in memory
	pthread_mutex_lock(&persistent.lock);
	remove_element(fold,sourcename);
	pthread_mutex_unlock(&persistent.lock);
	// Exit
	return 0;
}

int make_dir(const char *path) {
	// Get the time (this number is sent with the parameters of the request, so I keep it this way). The time is expressed in number of milliseconds since January 1st, 1970, in the Unix fashion
	time_t tt=time(0);
	char stime[20];
	sprintf(stime,"%li000",(unsigned long)tt);
	// Get the source and destination paths
	char basefolder[PATH_SIZE];
	char newname[PATH_SIZE];
	char baseid[PATH_SIZE];
	char actionuri[PATH_SIZE];
	unsigned long psize,bsize;
	char *sep="----------------------1345564553545";
	size_t lsep=strlen(sep);;
	char *head,*body,*p,*q,*page;
	FILE *fd;
	get_path_and_name(path,basefolder,newname);
	Folder *fold;
	int code=find_folder(basefolder,persistent.tree,&fold);
	if (code!=0) return code;
	// Load the parent folder to find the request uri
	if (get_folder(fold,1)!=0) return -1;
	get_id(fold,baseid);
	// Send a request for the delete form and retrieve the action URi
	bsize=43+strlen(stime);
	body=(char*)malloc(bsize);
	sprintf(body,"xajax=newajax_ajaxfichiers_create&xajaxr=%s",stime);
	fd=get_page(fold->file->requesturi,body,&psize);
	free(body);
	if (fd==0) return -1;
	page=mmap(0,psize+1,PROT_READ,MAP_SHARED,fileno(fd),0);	// Pointer to the response
	fclose(fd);
	if (page==MAP_FAILED) return -1;
	p=strstr(page,"id=\"AgTgtCreateForm\" class=\"form\" action=\"");
	if (p==0) {munmap((void*)page,psize);return -1;}
	p+=42;
	q=strchr(p,'"');
	strncpy(actionuri,p,q-p);
	actionuri[q-p]=0;
	munmap((void*)page,psize);
	// Finally, send the makedir command
	head=malloc(47+lsep);
	sprintf(head,"Content-Type: multipart/form-data; boundary=%s\r\n",sep);
	bsize=191+2*4*strlen(sep)+strlen(newname)+strlen(baseid);
	body=(char*)malloc(bsize);
	sprintf(body,"--%s\r\nContent-Disposition: form-data; name=\"folder_name[]\"\r\n\r\n%s\r\n--%s\r\nContent-Disposition: form-data; name=\"id_parent\"\r\n\r\n%s\r\n--%s\r\nContent-Disposition: form-data; name=\"submitButton\"\r\n\r\nAdd\r\n--%s--\r\n",sep,newname,sep,baseid,sep,sep);
	code=send_custom(0,persistent.hostinfo,persistent.host,actionuri,head,body,persistent.cookies);
	free(head);
	free(body);
	if (code!=0) return code;
	// Make the tree structure in memory out of date
	pthread_mutex_lock(&persistent.lock);
	free_folder(fold->elements);
	fold->elements=0;
	fold->file->updated=0;
	pthread_mutex_unlock(&persistent.lock);
	// Exit
	return 0;
}
